#ifndef RadioHead_h
#define RadioHead_h

// Official version numbers are maintained automatically by Makefile:
#define RH_VERSION_MAJOR 1
#define RH_VERSION_MINOR 116

// Symbolic names for currently supported platform types
#define RH_PLATFORM_ARDUINO          1
#define RH_PLATFORM_MSP430           2
#define RH_PLATFORM_STM32            3
#define RH_PLATFORM_GENERIC_AVR8     4
#define RH_PLATFORM_UNO32            5
#define RH_PLATFORM_UNIX             6
#define RH_PLATFORM_STM32STD         7
#define RH_PLATFORM_STM32F4_HAL      8
#define RH_PLATFORM_RASPI            9
#define RH_PLATFORM_NRF51            10
#define RH_PLATFORM_ESP8266          11
#define RH_PLATFORM_STM32F2          12
#define RH_PLATFORM_CHIPKIT_CORE     13
#define RH_PLATFORM_ESP32            14
#define RH_PLATFORM_NRF52            15
#define RH_PLATFORM_MONGOOSE_OS      16
#define RH_PLATFORM_ATTINY           17
// Spencer Kondes megaTinyCore:
#define RH_PLATFORM_ATTINY_MEGA      18
#define RH_PLATFORM_STM32L0          19

////////////////////////////////////////////////////
// Select platform automatically, if possible
#ifndef RH_PLATFORM
#if (defined(MPIDE) && MPIDE>=150 && defined(ARDUINO))
// Using ChipKIT Core on Arduino IDE
#define RH_PLATFORM RH_PLATFORM_CHIPKIT_CORE
#elif defined(MPIDE)
// Uno32 under old MPIDE, which has been discontinued:
#define RH_PLATFORM RH_PLATFORM_UNO32
#elif defined(NRF51) || defined(NRF52)
#define RH_PLATFORM RH_PLATFORM_NRF51
#elif defined(NRF52)
#define RH_PLATFORM RH_PLATFORM_NRF52
#elif defined(ESP8266)
#define RH_PLATFORM RH_PLATFORM_ESP8266
#elif defined(ESP32)
#define RH_PLATFORM RH_PLATFORM_ESP32
#elif defined(STM32L0) || defined(ARDUINO_ARCH_STM32L0)
#define RH_PLATFORM RH_PLATFORM_STM32L0
#elif defined(MGOS)
#define RH_PLATFORM RH_PLATFORM_MONGOOSE_OS
#elif defined(MEGATINYCORE) || defined(ARDUINO_attinyxy2) || defined(ARDUINO_attinyxy4) || defined(ARDUINO_attinyxy6) || defined(ARDUINO_attinyxy7)
#define RH_PLATFORM RH_PLATFORM_ATTINY_MEGA
#elif defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtinyX4__) || defined(__AVR_ATtinyX5__) || defined(__AVR_ATtiny2313__) || defined(__AVR_ATtiny4313__) || defined(__AVR_ATtinyX313__) || defined(ARDUINO_attiny)
#define RH_PLATFORM RH_PLATFORM_ATTINY
#elif defined(ARDUINO)
#define RH_PLATFORM RH_PLATFORM_ARDUINO
#elif defined(__MSP430G2452__) || defined(__MSP430G2553__)
#define RH_PLATFORM RH_PLATFORM_MSP430
#elif defined(MCU_STM32F103RE)
#define RH_PLATFORM RH_PLATFORM_STM32
#elif defined(STM32F2XX)
#define RH_PLATFORM RH_PLATFORM_STM32F2
#elif defined(USE_STDPERIPH_DRIVER)
#define RH_PLATFORM RH_PLATFORM_STM32STD
#elif defined(RASPBERRY_PI)
#define RH_PLATFORM RH_PLATFORM_RASPI
#elif defined(__unix__) // Linux
#define RH_PLATFORM RH_PLATFORM_UNIX
#elif defined(__APPLE__) // OSX
#define RH_PLATFORM RH_PLATFORM_UNIX
#else
#error Platform not defined!
#endif
#endif

////////////////////////////////////////////////////
// Platform specific headers:
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO)
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <wiring.h>
#endif
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL
#if defined(ARDUINO_ARCH_STM32F4)
// output to Serial causes hangs on STM32 F4 Discovery board
// There seems to be no way to output text to the USB connection
#undef Serial
#define Serial Serial2
#endif
#elif (RH_PLATFORM == RH_PLATFORM_ATTINY)
#include <Arduino.h>
//  #warning Arduino TinyCore does not support hardware SPI. Use software SPI instead.
#elif (RH_PLATFORM == RH_PLATFORM_ATTINY_MEGA)
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL
// On most AT_TINY_MEGA, Timer A is used for millis/micros, and B 0 or 1 for Tone by default.
// But not all devices support TCB1, so we use TCB0 on some variants.
// This is the same strategy for timer selection that Tone uses:
#if defined(MILLIS_USE_TIMERB0) && defined(TCB1)
#define RH_ATTINY_MEGA_ASK_TIMER TCB1
#define RH_ATTINY_MEGA_ASK_TIMER_VECTOR TCB1_INT_vect
#else
#define RH_ATTINY_MEGA_ASK_TIMER TCB0
#define RH_ATTINY_MEGA_ASK_TIMER_VECTOR TCB0_INT_vect
#endif

#elif (RH_PLATFORM == RH_PLATFORM_ESP8266) // ESP8266 processor on Arduino IDE
#include <Arduino.h>
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL
#define RH_MISSING_SPIUSINGINTERRUPT

#elif (RH_PLATFORM == RH_PLATFORM_ESP32)   // ESP32 processor on Arduino IDE
#include <Arduino.h>
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL
#define RH_MISSING_SPIUSINGINTERRUPT

#elif (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS) // Mongoose OS platform
#include <mgos.h>
#include <mgos_adc.h>
#include <mgos_pwm.h>
#include <MGOSCompat/HardwareSerial.h>
#include <MGOSCompat/HardwareSPI.h>
#include <MGOSCompat/MGOS.h>
#include <math.h> // We use the floor() math function.
#define RH_HAVE_HARDWARE_SPI
//If a Radio is connected via a serial port then this defines the serial
//port the radio is connected to.
#if defined(RH_SERIAL_PORT)
#if RH_SERIAL_PORT == 0
#define Serial Serial0
#elif RH_SERIAL_PORT == 1
#define Serial Serial1
#elif RH_SERIAL_PORT == 2
#define Serial Serial2
#endif
#else
#warning "RH_SERIAL_PORT not defined. Therefore serial port 0 selected"
#define Serial Serial0
#endif
#define RH_HAVE_SERIAL

#elif (RH_PLATFORM == RH_PLATFORM_MSP430) // LaunchPad specific
#include "legacymsp430.h"
#include "Energia.h"
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL

#elif (RH_PLATFORM == RH_PLATFORM_UNO32 || RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE)
#include <WProgram.h>
#include <string.h>
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define memcpy_P memcpy
#define RH_HAVE_SERIAL

#elif (RH_PLATFORM == RH_PLATFORM_STM32) // Maple, Flymaple etc
#include <STM32ArduinoCompat/wirish.h>
#include <stdint.h>
#include <string.h>
#include <STM32ArduinoCompat/HardwareSPI.h>
#define RH_HAVE_HARDWARE_SPI
// Defines which timer to use on Maple
#define MAPLE_TIMER 1
#define PROGMEM
#define memcpy_P memcpy
#define Serial SerialUSB
#define RH_HAVE_SERIAL

#elif (RH_PLATFORM == RH_PLATFORM_STM32L0)  // https://github.com/GrumpyOldPizza/ArduinoCore-stm32l0
#include <Arduino.h>
#include <SPI.h>
#include <stm32l0_gpio.h>
#include <stm32l0_exti.h>
#include <stm32l0_rtc.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL

#elif (RH_PLATFORM == RH_PLATFORM_STM32F2) // Particle Photon with firmware-develop
#include <stm32f2xx.h>
#include <application.h>
#include <math.h> // floor
#define RH_HAVE_SERIAL
#define RH_HAVE_HARDWARE_SPI

#elif (RH_PLATFORM == RH_PLATFORM_STM32STD) // STM32 with STM32F4xx_StdPeriph_Driver
#include <stm32f4xx.h>
#include <wirish.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <HardwareSPI.h>
#define RH_HAVE_HARDWARE_SPI
#define Serial SerialUSB
#define RH_HAVE_SERIAL

#elif (RH_PLATFORM == RH_PLATFORM_GENERIC_AVR8)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include <stdbool.h>
#define RH_HAVE_HARDWARE_SPI
#include <SPI.h>

// For Steve Childress port to ARM M4 w/CMSIS with STM's Hardware Abstraction lib.
// See ArduinoWorkarounds.h (not supplied)
#elif (RH_PLATFORM == RH_PLATFORM_STM32F4_HAL)
#include <ArduinoWorkarounds.h>
#include <stm32f4xx.h> // Also using ST's CubeMX to generate I/O and CPU setup source code for IAR/EWARM, not GCC ARM.
#include <stdint.h>
#include <string.h>
#include <math.h>
#define RH_HAVE_HARDWARE_SPI // using HAL (Hardware Abstraction Libraries from ST along with CMSIS, not arduino libs or pins concept.

#elif (RH_PLATFORM == RH_PLATFORM_RASPI)
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL
#define PROGMEM
// You can enable MUTEX to protect critical sections for multithreading
// #define RH_USE_MUTEX
#if (__has_include (<pigpio.h>))
#include <RHutil_pigpio/RasPi.h>
#else
#include <RHutil/RasPi.h>
#endif
#include <string.h>
//Define SS for CS0 or pin 24
#define SS 8

#elif (RH_PLATFORM == RH_PLATFORM_NRF51)
#define RH_HAVE_SERIAL
#define PROGMEM
#include <Arduino.h>

#elif (RH_PLATFORM == RH_PLATFORM_NRF52)
#include <SPI.h>
#define RH_HAVE_HARDWARE_SPI
#define RH_HAVE_SERIAL
#define PROGMEM
#include <Arduino.h>

#elif (RH_PLATFORM == RH_PLATFORM_UNIX)
// Simulate the sketch on Linux and OSX
#include <RHutil/simulator.h>
#define RH_HAVE_SERIAL
#include <netinet/in.h> // For htons and friends

#else
#error Platform unknown!
#endif

////////////////////////////////////////////////////
// This is an attempt to make a portable atomic block
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO)
#if defined(__arm__)
#include <RHutil/atomic.h>
#else
#include <util/atomic.h>
#endif
#define ATOMIC_BLOCK_START     ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
#define ATOMIC_BLOCK_END }
#elif (RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE)
// UsingChipKIT Core on Arduino IDE
#define ATOMIC_BLOCK_START unsigned int __status = disableInterrupts(); {
#define ATOMIC_BLOCK_END } restoreInterrupts(__status);
#elif (RH_PLATFORM == RH_PLATFORM_UNO32)
// Under old MPIDE, which has been discontinued:
#include <peripheral/int.h>
#define ATOMIC_BLOCK_START unsigned int __status = INTDisableInterrupts(); {
#define ATOMIC_BLOCK_END } INTRestoreInterrupts(__status);
#elif (RH_PLATFORM == RH_PLATFORM_STM32L0)
#define ATOMIC_BLOCK_START uint32_t primask = __get_PRIMASK(); __disable_irq(); {
#define ATOMIC_BLOCK_END } __set_PRIMASK(primask);
#elif (RH_PLATFORM == RH_PLATFORM_STM32F2) // Particle Photon with firmware-develop
#define ATOMIC_BLOCK_START { int __prev = HAL_disable_irq();
#define ATOMIC_BLOCK_END  HAL_enable_irq(__prev); }
#elif (RH_PLATFORM == RH_PLATFORM_ESP8266)
// See hardware/esp8266/2.0.0/cores/esp8266/Arduino.h
#define ATOMIC_BLOCK_START { uint32_t __savedPS = xt_rsil(15);
#define ATOMIC_BLOCK_END xt_wsr_ps(__savedPS);}
#else
// TO BE DONE:
#define ATOMIC_BLOCK_START
#define ATOMIC_BLOCK_END
#endif

////////////////////////////////////////////////////
// Try to be compatible with systems that support yield() and multitasking
// instead of spin-loops
// Recent Arduino IDE or Teensy 3 has yield()
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO && ARDUINO >= 155) || (defined(TEENSYDUINO) && defined(__MK20DX128__))
#define YIELD yield();
#elif (RH_PLATFORM == RH_PLATFORM_ESP8266)
// ESP8266 also has it
#define YIELD yield();
#elif (RH_PLATFORM == RH_PLATFORM_STM32L0)
#define YIELD yield();
#elif (RH_PLATFORM == RH_PLATFORM_MONGOOSE_OS)
//ESP32 and ESP8266 use freertos so we include calls
//that we would normall exit a function and return to
//the rtos in mgosYield() (E.G flush TX uart buffer
extern "C" {
  void mgosYield(void);
}
#define YIELD mgosYield()
#else
#define YIELD
#endif

////////////////////////////////////////////////////
// digitalPinToInterrupt is not available prior to Arduino 1.5.6 and 1.0.6
// See http://arduino.cc/en/Reference/attachInterrupt
#ifndef NOT_AN_INTERRUPT
#define NOT_AN_INTERRUPT -1
#endif
#ifndef digitalPinToInterrupt
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && !defined(__arm__)

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// Arduino Mega, Mega ADK, Mega Pro
// 2->0, 3->1, 21->2, 20->3, 19->4, 18->5
#define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : ((p) >= 18 && (p) <= 21 ? 23 - (p) : NOT_AN_INTERRUPT)))

#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
// Arduino 1284 and 1284P - See Manicbug and Optiboot
// 10->0, 11->1, 2->2
#define digitalPinToInterrupt(p) ((p) == 10 ? 0 : ((p) == 11 ? 1 : ((p) == 2 ? 2 : NOT_AN_INTERRUPT)))

#elif defined(__AVR_ATmega32U4__)
// Leonardo, Yun, Micro, Pro Micro, Flora, Esplora
// 3->0, 2->1, 0->2, 1->3, 7->4
#define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT)))))

#else
// All other arduino except Due:
// Serial Arduino, Extreme, NG, BT, Uno, Diecimila, Duemilanove, Nano, Menta, Pro, Mini 04, Fio, LilyPad, Ethernet etc
// 2->0, 3->1
#define digitalPinToInterrupt(p)  ((p) == 2 ? 0 : ((p) == 3 ? 1 : NOT_AN_INTERRUPT))

#endif

#elif (RH_PLATFORM == RH_PLATFORM_UNO32) || (RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE)
// Hmmm, this is correct for Uno32, but what about other boards on ChipKIT Core?
#define digitalPinToInterrupt(p) ((p) == 38 ? 0 : ((p) == 2 ? 1 : ((p) == 7 ? 2 : ((p) == 8 ? 3 : ((p) == 735 ? 4 : NOT_AN_INTERRUPT)))))

#else
// Everything else (including Due and Teensy) interrupt number the same as the interrupt pin number
#define digitalPinToInterrupt(p) (p)
#endif
#endif

// On some platforms, attachInterrupt() takes a pin number, not an interrupt number
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_SAM_DUE)) || defined(ARDUINO_ARCH_STM32L0)
#define RH_ATTACHINTERRUPT_TAKES_PIN_NUMBER
#endif

// Slave select pin, some platforms such as ATTiny do not define it.
// ESP32 pins_arduino.h uses static const uint8_t SS = <UINT>; instead
// of a #define to declare the SS constant.
#if (RH_PLATFORM != RH_PLATFORM_ESP32)
#ifndef SS
#define SS 10
#endif
#endif

// Some platforms require special attributes for interrupt routines
#if (RH_PLATFORM == RH_PLATFORM_ESP8266)
// interrupt handler and related code must be in RAM on ESP8266,
// according to issue #46.
#define RH_INTERRUPT_ATTR ICACHE_RAM_ATTR

#elif (RH_PLATFORM == RH_PLATFORM_ESP32)
#define RH_INTERRUPT_ATTR IRAM_ATTR
#else
#define RH_INTERRUPT_ATTR
#endif

// These defs cause trouble on some versions of Arduino
#undef abs
#undef round
#undef double

// Sigh: there is no widespread adoption of htons and friends in the base code, only in some WiFi headers etc
// that have a lot of excess baggage
#if RH_PLATFORM != RH_PLATFORM_UNIX && !defined(htons)
// #ifndef htons
// These predefined macros available on modern GCC compilers
#if   __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
// Atmel processors
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
#define ntohs(x) htons(x)
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) |	\
                   ((x)<< 8 & 0x00FF0000UL) |	\
                   ((x)>> 8 & 0x0000FF00UL) |	\
                   ((x)>>24 & 0x000000FFUL) )
#define ntohl(x) htonl(x)

#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// Others
#define htons(x) (x)
#define ntohs(x) (x)
#define htonl(x) (x)
#define ntohl(x) (x)

#else
#error "RadioHead.h: Dont know how to define htons and friends for this processor"
#endif
#endif

// Some platforms need a mutex for multihreaded case
#ifdef RH_USE_MUTEX
#include <pthread.h>
#define RH_DECLARE_MUTEX(X) pthread_mutex_t X;
#define RH_MUTEX_INIT(X) pthread_mutex_init(&X, NULL)
#define RH_MUTEX_LOCK(X) pthread_mutex_lock(&X)
#define RH_MUTEX_UNLOCK(X) pthread_mutex_unlock(&X)
#else
#define RH_DECLARE_MUTEX(X)
#define RH_MUTEX_INIT(X)
#define RH_MUTEX_LOCK(X)
#define RH_MUTEX_UNLOCK(X)
#endif

// This is the address that indicates a broadcast
#define RH_BROADCAST_ADDRESS 0xff

// Specifies an invalid IO pin selection
#define RH_INVALID_PIN       0xff

// Uncomment this is to enable Encryption (see RHEncryptedDriver):
// But ensure you have installed the Crypto directory from arduinolibs first:
// http://rweather.github.io/arduinolibs/index.html
//#define RH_ENABLE_ENCRYPTION_MODULE

// Some platforms like RocketScream need this to see debug Serial output from within RH
// and if it goes to Serial, get a hang after a few minutes.
//#define Serial SerialUSB

#endif
